package cmd

import (
	"context"
	"fmt"
	_ "mldong/internal/modules/sys/controller" // 确保所有sys控制器包被导入
	"mldong/utility"
	"net/http"
	"strings"

	"github.com/gogf/gf/v2/container/garray"
	"github.com/gogf/gf/v2/frame/g"
	"github.com/gogf/gf/v2/net/ghttp"
	"github.com/gogf/gf/v2/os/gcmd"
	"github.com/golang-jwt/jwt/v5"

	"mldong/api/base"
	"mldong/internal/consts"
)

// ErrorHandlerMiddleware 错误处理中间件
func ErrorHandlerMiddleware(r *ghttp.Request) {
	r.Middleware.Next()

	var (
		msg string
		err = r.GetError()
	)
	if err != nil {
		msg = err.Error()
		r.Response.WriteJson(base.FailWithDefaultCode(msg))
	}
}

// 优化提示词：使用AuthMap去获取对应的权限码，如果存在，则使用里面的规则，如果不存在，则使用原有的默认规则，如果存在多个值，即使用逗号分割，则判断mode的方式如：or或才and，来判断。
// 权限认证中间件
func AuthMiddleware(r *ghttp.Request) {
	// 如果为白名单请求，则直接通过
	var WhiteList = garray.NewStrArrayFrom(consts.WhiteList)
	if WhiteList.Contains(r.URL.Path) {
		r.Middleware.Next()
		return
	}
	var TokenPrefix = consts.TokenPrefix
	var tokenString = r.Header.Get(consts.TokenName)
	// 去掉TokenPrefix
	if len(tokenString) <= len(TokenPrefix) {
		r.Response.WriteJson(base.Fail(99990403, "token无效"))
		r.Exit()
	}
	tokenString = tokenString[len(TokenPrefix):]

	token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
		return []byte(consts.JwtKey), nil
	})
	if err != nil || !token.Valid {
		fmt.Println(err)
		r.Response.WriteJson(base.Fail(99990403, "token无效"))
		r.Exit()
	}

	// 从 JWT 中提取 PermCodes
	claims, ok := token.Claims.(jwt.MapClaims)
	if !ok {
		r.Response.WriteJson(base.Fail(99990403, "token无效"))
		r.Exit()
	}
	// 获取当前用户id
	userId, ok := claims["ID"].(string)
	if !ok {
		r.Response.WriteJson(base.Fail(99990403, "用户ID不存在"))
		r.Exit()
	}
	r.SetCtxVar(consts.UserIdKey, userId)
	permCodes, ok := claims["PermCodes"].([]interface{})
	if !ok {
		r.Response.WriteJson(base.Fail(99990406, "权限不足"))
		r.Exit()
	}

	// 将权限码转换为字符串数组
	var permCodeList []string
	for _, code := range permCodes {
		permCodeList = append(permCodeList, code.(string))
	}

	// 如果用户拥有 admin 权限码，则允许访问所有接口
	if garray.NewStrArrayFrom(permCodeList).Contains(consts.SuperAdminAuthKey) {
		r.Middleware.Next()
		return
	}

	// 获取请求路径对应的权限规则
	authRule, exists := consts.AuthMap[r.URL.Path]
	if exists {
		// 如果存在权限规则，则根据规则进行校验
		requiredPerms := strings.Split(authRule["value"], ",")
		mode := authRule["mode"]
		if mode == "" {
			// 如果没有指定模式，则使用默认模式（or）
			mode = "or"
		}
		fmt.Println("mode:" + mode)
		if mode == "or" {
			// or 模式：用户只需拥有任意一个权限码即可
			var hasPerm bool
			for _, perm := range requiredPerms {
				if garray.NewStrArrayFrom(permCodeList).Contains(perm) {
					hasPerm = true
					break
				}
			}
			if !hasPerm {
				r.Response.WriteJson(base.Fail(99990406, "权限不足"))
				r.Exit()
			}
		} else if mode == "and" {
			// and 模式：用户需拥有所有权限码
			for _, perm := range requiredPerms {
				if !garray.NewStrArrayFrom(permCodeList).Contains(perm) {
					r.Response.WriteJson(base.Fail(99990406, "权限不足"))
					r.Exit()
				}
			}
		}
	} else {
		// 如果不存在权限规则，则使用默认规则
		permCode := strings.Replace(strings.Replace(r.URL.Path, "/", ":", -1), ":", "", 1)
		if !garray.NewStrArrayFrom(permCodeList).Contains(permCode) {
			r.Response.WriteJson(base.Fail(99990406, "权限不足"))
			r.Exit()
		}
	}
	r.Middleware.Next()
}

var (
	Main = gcmd.Command{
		Name:  "main",
		Usage: "main",
		Brief: "start http server",
		Func: func(ctx context.Context, parser *gcmd.Parser) (err error) {
			// 初始化配置
			// 通常在main.go中初始化
			errInit := utility.InstanceConstantContext().InitConstantContext(ctx)
			if errInit != nil {
				// 处理初始化错误
				panic(errInit)
			}
			s := g.Server()
			// 统一错误处理
			s.BindStatusHandler(404, func(r *ghttp.Request) {
				r.Response.Status = http.StatusOK
				r.Response.WriteJson(base.Fail(99990404, "接口不存在此功能正在建设中，敬请期待！"))
			})
			s.BindStatusHandler(500, func(r *ghttp.Request) {
				r.Response.Status = http.StatusOK
				r.Response.WriteJson(base.Fail(99990500, "服务器内部错误"))
			})
			s.Group("/", func(group *ghttp.RouterGroup) {
				//group.Middleware(ghttp.MiddlewareHandlerResponse)
				group.Middleware(AuthMiddleware, ErrorHandlerMiddleware)
				// group.Bind(
				// 	controller.NewUserController(),
				// 	controller.NewRoleController(),
				// 	controller.NewAuthController(),
				// 	controller.NewPostController(),
				// )
				group.Bind(utility.GetControllers()...)
			})
			s.Run()
			return nil
		},
	}
)
